package ch.sv7.tool.dbmanager.db.script;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

import ch.sv7.tool.dbmanager.DbManagerException;
import ch.sv7.tool.dbmanager.db.ColumnType;
import ch.sv7.tool.dbmanager.db.Field;
import ch.sv7.tool.dbmanager.db.FilePatternManager;
import ch.sv7.tool.dbmanager.db.Row;
import ch.sv7.tool.dbmanager.db.Table;
import ch.sv7.tool.dbmanager.db.TableSchema;
import ch.sv7.tool.dbmanager.db.TableWriter;

public class ScriptTableWriter implements TableWriter {

	private String directory;

	private String schemaName;

	private String filePattern;

	private PrintWriter file;

	public ScriptTableWriter(String directory, String schemaName, String filePattern) {
		this.directory = directory;
		this.schemaName = schemaName;
		this.filePattern = filePattern;
	}

	public void writeTable(Table table, TableSchema schema) throws DbManagerException {
		writeHeader(schema);
		for (int i = 0; i < table.size(); i++)
			writeRow(table.getRowAt(i), schema);

		writeFooter(schema);
	}

	public void writeFooter(TableSchema tableschema) throws DbManagerException {
		file.flush();
		file.close();
	}

	public void writeHeader(TableSchema tableschema) throws DbManagerException {
		String filename = directory + System.getProperty("file.separator")
				+ FilePatternManager.getFilename(tableschema.getName(), schemaName, filePattern) + ".sql";
		try {
			file = new PrintWriter(new FileOutputStream(filename));
		} catch (FileNotFoundException e) {
			throw new DbManagerException("Unable to create file : " + filename, e);
		}
	}

	public void writeRow(Row row, TableSchema tableschema) throws DbManagerException {
		file.println(getRowInsert(row, tableschema));
	}

	private String getRowInsert(Row row, TableSchema schema) {
		StringBuffer insert = new StringBuffer();
		insert.append("INSERT INTO " + schema.getFullName() + " (");
		for (int i = 0; i < schema.getColumnSchemas().length; i++) {
			if (i != 0)
				insert.append(", ");
			Field field = row.getField(schema.getColumnSchemas()[i].getName());
			insert.append(field.getName());
		}

		insert.append(") VALUES (");
		for (int i = 0; i < schema.getColumnSchemas().length; i++) {
			if (i != 0)
				insert.append(", ");
			Field field = row.getField(schema.getColumnSchemas()[i].getName());
			insert.append(getFieldString(field, schema.getColumnSchemas()[i].getType()));
		}

		insert.append(");");
		return insert.toString();
	}

	private String getFieldString(Field field, ColumnType dataType) {
		Object value = field.getValue();
		if (value == null)
			return "NULL";
		if (dataType.isBinary()) {
			System.out.println("WARNING, replacing binary value by NULL in script !");
			return "NULL";
		}
		if (dataType.mustBeQuoted())
			return safeQuoteString(value.toString());
		else
			return value.toString();
	}

	private static String safeQuoteString(String str) {
		if (str.indexOf("'") == -1)
			return "'" + str + "'";
		else
			return "'" + replaceAllToken(str, "'", "''") + "'";
	}

	private static String replaceAllToken(String str, String pattern, String replace) {
		if (str == null || pattern == null || replace == null)
			return str;
		int searchPos = 0;
		for (int pos = str.indexOf(pattern, searchPos); pos != -1; pos = str.indexOf(pattern, searchPos)) {
			str = str.substring(0, pos) + replace + str.substring(pos + pattern.length());
			searchPos = pos + replace.length();
		}

		return str;
	}
}
